# pandas, numpy, seaborn을 불러옵니다.
import pandas as pd # 데이터 분석
import numpy as np # 수치 계싼용
import seaborn as sns # 데이터 시각화
import matplotlib.pyplot as plt # 그래프 사이즈, 한글 폰트
# 구버전의 주피터 노트북에서 그래프가 보이는 설정
%matplotlib inline
# plt.rc("font", family="Malgun Gothic")
plt.rc("font", family="AppleGothic")
plt.rc("axes", unicode_minus=False)
# 폰트가 선명하게 보이도록 설정
from IPython.display import set_matplotlib_formats
set_matplotlib_formats("retina")
# 한글폰트와 마이너스 폰트 설정 확인
plt.title("한글폰트 설정")
plt.plot([-4, -6, 1, 2, 0, 3])
[<matplotlib.lines.Line2D at 0x7fd441b33ca0>]
# # 나눔고딕 설치
# !apt -qq -y install fonts-nanum > /dev/null
# import matplotlib.font_manager as fm
# fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
# font = fm.FontProperties(fname=fontpath, size=9)
# fm._rebuild()
# # 그래프에 retina display 적용
# %config InlineBackend.figure_format = 'retina'
# # Colab 의 한글 폰트 설정
# plt.rc('font', family='NanumBarunGothic')
# # 구글 드라이브에서 csv 파일을 읽어오기 위해 gauth 인증
# !pip install -U -q PyDrive
# from pydrive.auth import GoogleAuth
# from pydrive.drive import GoogleDrive
# from google.colab import auth
# from oauth2client.client import GoogleCredentials
# # PyDrive client 인증
# auth.authenticate_user()
# gauth = GoogleAuth()
# gauth.credentials = GoogleCredentials.get_application_default()
# drive = GoogleDrive(gauth)
# # 공유 가능한 링크로 파일 가져오기
# url = 'https://drive.google.com/open?id=1e91PH_KRFxNXUsx8Hi-Q2vPiorCDsOP4'
# id = url.split('=')[1]
# print(id)
# downloaded = drive.CreateFile({'id':id})
# # data 폴더에 파일을 관리하며, 폴더가 없다면 만들어서 파일을 관리하도록 한다.
# %mkdir data
# downloaded.GetContentFile('data/상가업소정보_201912_01.csv')
# 파일을 불러와 df 라는 변수에 담습니다.
df = pd.read_csv("data/상가업소정보_201912_01.csv", sep='|')
df.head()
# 이 데이터는 지역별로 파일이 구분되어 있음
| 상가업소번호 | 상호명 | 지점명 | 상권업종대분류코드 | 상권업종대분류명 | 상권업종중분류코드 | 상권업종중분류명 | 상권업종소분류코드 | 상권업종소분류명 | 표준산업분류코드 | ... | 건물관리번호 | 건물명 | 도로명주소 | 구우편번호 | 신우편번호 | 동정보 | 층정보 | 호정보 | 경도 | 위도 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 19905471 | 와라와라호프 | NaN | Q | 음식 | Q09 | 유흥주점 | Q09A01 | 호프/맥주 | I56219 | ... | 1168010600106040000014378 | 대치상가 | 서울특별시 강남구 남부순환로 2933 | 135280 | 6280.0 | NaN | 1 | NaN | 127.061026 | 37.493922 |
| 1 | 19911397 | 커피빈코리아선릉로93길점 | 코리아선릉로93길점 | Q | 음식 | Q12 | 커피점/카페 | Q12A01 | 커피전문점/카페/다방 | I56220 | ... | 1168010100106960042022041 | NaN | 서울특별시 강남구 선릉로93길 6 | 135080 | 6149.0 | NaN | 1 | NaN | 127.047883 | 37.505675 |
| 2 | 19911801 | 프로포즈 | NaN | Q | 음식 | Q09 | 유흥주점 | Q09A01 | 호프/맥주 | I56219 | ... | 1154510200101620001017748 | NaN | 서울특별시 금천구 가산로 34-6 | 153010 | 8545.0 | NaN | 1 | NaN | 126.899220 | 37.471711 |
| 3 | 19912201 | 싱싱커피&토스트 | NaN | Q | 음식 | Q07 | 패스트푸드 | Q07A10 | 토스트전문 | I56192 | ... | 2653010400105780000002037 | 산업용품유통상가 | 부산광역시 사상구 괘감로 37 | 617726 | 46977.0 | NaN | 1 | 26 | 128.980455 | 35.159774 |
| 4 | 19932756 | 가락사우나내스낵 | NaN | F | 생활서비스 | F09 | 대중목욕탕/휴게 | F09A02 | 사우나/증기탕/온천 | S96121 | ... | 1171010500102560005010490 | NaN | 서울특별시 송파구 가락로 71 | 138846 | 5690.0 | NaN | 1 | NaN | 127.104071 | 37.500249 |
5 rows × 39 columns
# shape 를 통해 불러온 csv 파일의 크기를 확인합니다.
df.shape
# 사용하지 않을 col도 많다.
(573680, 39)
# info 를 사용하면 데이터의 전체적인 정보를 볼 수 있습니다.
# 데이터의 사이즈, 타입, 메모리 사용량 등을 볼 수 있습니다.
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 573680 entries, 0 to 573679 Data columns (total 39 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 상가업소번호 573680 non-null int64 1 상호명 573679 non-null object 2 지점명 76674 non-null object 3 상권업종대분류코드 573680 non-null object 4 상권업종대분류명 573680 non-null object 5 상권업종중분류코드 573680 non-null object 6 상권업종중분류명 573680 non-null object 7 상권업종소분류코드 573680 non-null object 8 상권업종소분류명 573680 non-null object 9 표준산업분류코드 539290 non-null object 10 표준산업분류명 539290 non-null object 11 시도코드 573680 non-null int64 12 시도명 573680 non-null object 13 시군구코드 573680 non-null int64 14 시군구명 573680 non-null object 15 행정동코드 573680 non-null int64 16 행정동명 573680 non-null object 17 법정동코드 573680 non-null int64 18 법정동명 573680 non-null object 19 지번코드 573680 non-null int64 20 대지구분코드 573680 non-null int64 21 대지구분명 573680 non-null object 22 지번본번지 573680 non-null int64 23 지번부번지 474924 non-null float64 24 지번주소 573680 non-null object 25 도로명코드 573680 non-null int64 26 도로명 573680 non-null object 27 건물본번지 573680 non-null int64 28 건물부번지 71988 non-null float64 29 건물관리번호 573680 non-null object 30 건물명 265608 non-null object 31 도로명주소 573680 non-null object 32 구우편번호 573680 non-null int64 33 신우편번호 573671 non-null float64 34 동정보 50856 non-null object 35 층정보 347127 non-null object 36 호정보 85266 non-null object 37 경도 573680 non-null float64 38 위도 573680 non-null float64 dtypes: float64(5), int64(11), object(23) memory usage: 170.7+ MB
# isnull() 을 사용하면 데이터의 결측치를 볼 수 있습니다.
# 결측치는 True로 값이 있다면 False로 표시되는데 True 는 1과 같기 때문에
# True 값을 sum()을 사용해서 더하게 되면 합계를 볼 수 있습니다.
# mean()을 사용하면 결측치의 비율을 볼 수 있습니다.
df.isnull()
| 상가업소번호 | 상호명 | 지점명 | 상권업종대분류코드 | 상권업종대분류명 | 상권업종중분류코드 | 상권업종중분류명 | 상권업종소분류코드 | 상권업종소분류명 | 표준산업분류코드 | ... | 건물관리번호 | 건물명 | 도로명주소 | 구우편번호 | 신우편번호 | 동정보 | 층정보 | 호정보 | 경도 | 위도 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | False | False | True | False | False | False | False | False | False | False | ... | False | False | False | False | False | True | False | True | False | False |
| 1 | False | False | False | False | False | False | False | False | False | False | ... | False | True | False | False | False | True | False | True | False | False |
| 2 | False | False | True | False | False | False | False | False | False | False | ... | False | True | False | False | False | True | False | True | False | False |
| 3 | False | False | True | False | False | False | False | False | False | False | ... | False | False | False | False | False | True | False | False | False | False |
| 4 | False | False | True | False | False | False | False | False | False | False | ... | False | True | False | False | False | True | False | True | False | False |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 573675 | False | False | True | False | False | False | False | False | False | False | ... | False | True | False | False | False | True | True | True | False | False |
| 573676 | False | False | True | False | False | False | False | False | False | False | ... | False | False | False | False | False | True | False | True | False | False |
| 573677 | False | False | True | False | False | False | False | False | False | False | ... | False | False | False | False | False | True | False | True | False | False |
| 573678 | False | False | True | False | False | False | False | False | False | False | ... | False | False | False | False | False | True | False | True | False | False |
| 573679 | False | False | True | False | False | False | False | False | False | False | ... | False | False | False | False | False | False | True | True | False | False |
573680 rows × 39 columns
df.isnull().sum()
상가업소번호 0 상호명 1 지점명 497006 상권업종대분류코드 0 상권업종대분류명 0 상권업종중분류코드 0 상권업종중분류명 0 상권업종소분류코드 0 상권업종소분류명 0 표준산업분류코드 34390 표준산업분류명 34390 시도코드 0 시도명 0 시군구코드 0 시군구명 0 행정동코드 0 행정동명 0 법정동코드 0 법정동명 0 지번코드 0 대지구분코드 0 대지구분명 0 지번본번지 0 지번부번지 98756 지번주소 0 도로명코드 0 도로명 0 건물본번지 0 건물부번지 501692 건물관리번호 0 건물명 308072 도로명주소 0 구우편번호 0 신우편번호 9 동정보 522824 층정보 226553 호정보 488414 경도 0 위도 0 dtype: int64
df.isnull().mean()
# 결측치 비율
상가업소번호 0.000000 상호명 0.000002 지점명 0.866347 상권업종대분류코드 0.000000 상권업종대분류명 0.000000 상권업종중분류코드 0.000000 상권업종중분류명 0.000000 상권업종소분류코드 0.000000 상권업종소분류명 0.000000 표준산업분류코드 0.059946 표준산업분류명 0.059946 시도코드 0.000000 시도명 0.000000 시군구코드 0.000000 시군구명 0.000000 행정동코드 0.000000 행정동명 0.000000 법정동코드 0.000000 법정동명 0.000000 지번코드 0.000000 대지구분코드 0.000000 대지구분명 0.000000 지번본번지 0.000000 지번부번지 0.172145 지번주소 0.000000 도로명코드 0.000000 도로명 0.000000 건물본번지 0.000000 건물부번지 0.874515 건물관리번호 0.000000 건물명 0.537010 도로명주소 0.000000 구우편번호 0.000000 신우편번호 0.000016 동정보 0.911351 층정보 0.394912 호정보 0.851370 경도 0.000000 위도 0.000000 dtype: float64
df.isnull().mean().plot.barh(figsize=(7, 9))
<AxesSubplot:>
# drop을 하는 방법도 있지만 사용할 컬럼만 따로 모아서 보는 방법도 있습니다.
# 여기에서는 사용할 컬럼만 따로 모아서 사용합니다.
columns = ['상호명', '상권업종대분류명', '상권업종중분류명', '상권업종소분류명',
'시도명', '시군구명', '행정동명', '법정동명', '도로명주소',
'경도', '위도']
print(df.shape)
df = df[columns].copy() # df에 다시 담아주기
df.shape
# 39개였던 col이 11개로 줄었다.
# 이번 영상에서는 drop을 사용하지 않고 필요한 컬럼만 모아 다시 저장했다.
(573680, 39)
(573680, 11)
# 제거 후 메모리 사용량 보기
df.info()
# 170MB -> 48MB
<class 'pandas.core.frame.DataFrame'> RangeIndex: 573680 entries, 0 to 573679 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 상호명 573679 non-null object 1 상권업종대분류명 573680 non-null object 2 상권업종중분류명 573680 non-null object 3 상권업종소분류명 573680 non-null object 4 시도명 573680 non-null object 5 시군구명 573680 non-null object 6 행정동명 573680 non-null object 7 법정동명 573680 non-null object 8 도로명주소 573680 non-null object 9 경도 573680 non-null float64 10 위도 573680 non-null float64 dtypes: float64(2), object(9) memory usage: 48.1+ MB
# 시도명이 서울로 시작하는 데이터만 봅니다.
# 또, df_seoul 이라는 변수에 결과를 저장합니다.
# 새로운 변수에 데이터프레임을 할당할 때 copy()를 사용하는 것을 권장합니다.
df_seoul = df[df["시도명"] == "서울특별시"].copy()
print(df_seoul.shape)
df_seoul.head()
(407376, 11)
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 와라와라호프 | 음식 | 유흥주점 | 호프/맥주 | 서울특별시 | 강남구 | 대치1동 | 대치동 | 서울특별시 강남구 남부순환로 2933 | 127.061026 | 37.493922 |
| 1 | 커피빈코리아선릉로93길점 | 음식 | 커피점/카페 | 커피전문점/카페/다방 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 선릉로93길 6 | 127.047883 | 37.505675 |
| 2 | 프로포즈 | 음식 | 유흥주점 | 호프/맥주 | 서울특별시 | 금천구 | 독산3동 | 독산동 | 서울특별시 금천구 가산로 34-6 | 126.899220 | 37.471711 |
| 4 | 가락사우나내스낵 | 생활서비스 | 대중목욕탕/휴게 | 사우나/증기탕/온천 | 서울특별시 | 송파구 | 석촌동 | 석촌동 | 서울특별시 송파구 가락로 71 | 127.104071 | 37.500249 |
| 5 | 초밥왕 | 음식 | 일식/수산물 | 음식점-초밥전문 | 서울특별시 | 송파구 | 잠실6동 | 신천동 | 서울특별시 송파구 올림픽로 293-19 | 127.102490 | 37.515149 |
# unique 를 사용하면 중복을 제거한 시군구명을 가져옵니다.
# 그리고 shape로 갯수를 출력해 봅니다.
df_seoul["시군구명"].unique()
array(['강남구', '금천구', '송파구', '광진구', '강서구', '중구', '서초구', '성북구', '구로구',
'영등포구', '서대문구', '동대문구', '노원구', '동작구', '성동구', '관악구', '강동구', '양천구',
'종로구', '강북구', '은평구', '중랑구', '도봉구', '마포구', '용산구'], dtype=object)
# nunique 를 사용하면 중복을 제거한 시군구명의 갯수를 세어줍니다.
df_seoul["시군구명"].nunique()
25
# "seoul_open_store.csv" 라는 이름으로 저장합니다.
df_seoul.to_csv("seoul_open_store.csv")
# 제대로 저장이 되었는지 같은 파일을 불러와서 확인합니다.
pd.read_csv("seoul_open_store.csv")
# 그냥 불러오면 맨 앞에 Unname:0 이라는 col이 생김 (index값)
| Unnamed: 0 | 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 와라와라호프 | 음식 | 유흥주점 | 호프/맥주 | 서울특별시 | 강남구 | 대치1동 | 대치동 | 서울특별시 강남구 남부순환로 2933 | 127.061026 | 37.493922 |
| 1 | 1 | 커피빈코리아선릉로93길점 | 음식 | 커피점/카페 | 커피전문점/카페/다방 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 선릉로93길 6 | 127.047883 | 37.505675 |
| 2 | 2 | 프로포즈 | 음식 | 유흥주점 | 호프/맥주 | 서울특별시 | 금천구 | 독산3동 | 독산동 | 서울특별시 금천구 가산로 34-6 | 126.899220 | 37.471711 |
| 3 | 4 | 가락사우나내스낵 | 생활서비스 | 대중목욕탕/휴게 | 사우나/증기탕/온천 | 서울특별시 | 송파구 | 석촌동 | 석촌동 | 서울특별시 송파구 가락로 71 | 127.104071 | 37.500249 |
| 4 | 5 | 초밥왕 | 음식 | 일식/수산물 | 음식점-초밥전문 | 서울특별시 | 송파구 | 잠실6동 | 신천동 | 서울특별시 송파구 올림픽로 293-19 | 127.102490 | 37.515149 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 407371 | 573675 | 비파티세리공덕 | 음식 | 한식 | 한식/백반/한정식 | 서울특별시 | 마포구 | 공덕동 | 공덕동 | 서울특별시 마포구 마포대로14길 4 | 126.955059 | 37.548618 |
| 407372 | 573676 | 앤탑PC방 | 관광/여가/오락 | PC/오락/당구/볼링등 | 인터넷PC방 | 서울특별시 | 성동구 | 성수2가3동 | 성수동2가 | 서울특별시 성동구 성수일로8길 37 | 127.054615 | 37.545853 |
| 407373 | 573677 | 오즈아레나PC방 | 관광/여가/오락 | PC/오락/당구/볼링등 | 인터넷PC방 | 서울특별시 | 강남구 | 논현1동 | 논현동 | 서울특별시 강남구 강남대로 492 | 127.024102 | 37.506202 |
| 407374 | 573678 | 파인트리네일 | 생활서비스 | 이/미용/건강 | 발/네일케어 | 서울특별시 | 영등포구 | 여의동 | 여의도동 | 서울특별시 영등포구 국제금융로 10 | 126.924863 | 37.525172 |
| 407375 | 573679 | 마이리틀네일 | 생활서비스 | 이/미용/건강 | 발/네일케어 | 서울특별시 | 도봉구 | 창1동 | 창동 | 서울특별시 도봉구 도봉로114길 22-8 | 127.035145 | 37.647099 |
407376 rows × 12 columns
df_seoul.to_csv("seoul_open_store.csv", index=False)
pd.read_csv("seoul_open_store.csv")
# 이제 index 사라짐
# 다시 파일 들어가봐도 맨 앞에 ,(콤마) 사라짐을 알 수 있음
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 와라와라호프 | 음식 | 유흥주점 | 호프/맥주 | 서울특별시 | 강남구 | 대치1동 | 대치동 | 서울특별시 강남구 남부순환로 2933 | 127.061026 | 37.493922 |
| 1 | 커피빈코리아선릉로93길점 | 음식 | 커피점/카페 | 커피전문점/카페/다방 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 선릉로93길 6 | 127.047883 | 37.505675 |
| 2 | 프로포즈 | 음식 | 유흥주점 | 호프/맥주 | 서울특별시 | 금천구 | 독산3동 | 독산동 | 서울특별시 금천구 가산로 34-6 | 126.899220 | 37.471711 |
| 3 | 가락사우나내스낵 | 생활서비스 | 대중목욕탕/휴게 | 사우나/증기탕/온천 | 서울특별시 | 송파구 | 석촌동 | 석촌동 | 서울특별시 송파구 가락로 71 | 127.104071 | 37.500249 |
| 4 | 초밥왕 | 음식 | 일식/수산물 | 음식점-초밥전문 | 서울특별시 | 송파구 | 잠실6동 | 신천동 | 서울특별시 송파구 올림픽로 293-19 | 127.102490 | 37.515149 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 407371 | 비파티세리공덕 | 음식 | 한식 | 한식/백반/한정식 | 서울특별시 | 마포구 | 공덕동 | 공덕동 | 서울특별시 마포구 마포대로14길 4 | 126.955059 | 37.548618 |
| 407372 | 앤탑PC방 | 관광/여가/오락 | PC/오락/당구/볼링등 | 인터넷PC방 | 서울특별시 | 성동구 | 성수2가3동 | 성수동2가 | 서울특별시 성동구 성수일로8길 37 | 127.054615 | 37.545853 |
| 407373 | 오즈아레나PC방 | 관광/여가/오락 | PC/오락/당구/볼링등 | 인터넷PC방 | 서울특별시 | 강남구 | 논현1동 | 논현동 | 서울특별시 강남구 강남대로 492 | 127.024102 | 37.506202 |
| 407374 | 파인트리네일 | 생활서비스 | 이/미용/건강 | 발/네일케어 | 서울특별시 | 영등포구 | 여의동 | 여의도동 | 서울특별시 영등포구 국제금융로 10 | 126.924863 | 37.525172 |
| 407375 | 마이리틀네일 | 생활서비스 | 이/미용/건강 | 발/네일케어 | 서울특별시 | 도봉구 | 창1동 | 창동 | 서울특별시 도봉구 도봉로114길 22-8 | 127.035145 | 37.647099 |
407376 rows × 11 columns
# 문자열의 소문자로 변경하는 메소드를 사용합니다.
# "상호명_소문자" 컬럼을 만듭니다.
df_seoul["상호명_소문자"] = df_seoul["상호명"].str.lower()
df_seoul["상호명_소문자"].str.extract("(베|배)스킨라빈스|baskinrobbins")[0].value_counts()
배 347 베 117 Name: 0, dtype: int64
# baskinrobbins 를 "상호명_소문자" 컬럼으로 가져옵니다.
# 띄어쓰기 등의 다를 수 있기 때문에 앞글자 baskin 만 따서 가져오도록 합니다.
# '상호명_소문자'컬럼으로 '배스킨라빈스|baskin' 를 가져와 갯수를 세어봅니다.
# loc[행]
# loc[행, 열]
df_seoul[df_seoul["상호명_소문자"].str.contains("(베|배)스킨라빈스|baskinrobbins")].head()
# df_seoul[df_seoul["상호명_소문자"].str.contains("베스킨라빈스|배스킨라빈스|baskinrobbins")]
/Users/yeon/opt/anaconda3/lib/python3.8/site-packages/pandas/core/strings/accessor.py:101: UserWarning: This pattern has match groups. To actually get the groups, use str.extract. return func(self, *args, **kwargs)
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 76 | 배스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 관악구 | 청룡동 | 봉천동 | 서울특별시 관악구 관악로 161 | 126.952166 | 37.479599 | 배스킨라빈스 |
| 2164 | 베스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 마포구 | 서교동 | 서교동 | 서울특별시 마포구 와우산로 88 | 126.923809 | 37.552104 | 베스킨라빈스 |
| 11060 | 베스킨라빈스은행나무점 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 금천구 | 시흥5동 | 시흥동 | 서울특별시 금천구 금하로 726-1 | 126.910405 | 37.450433 | 베스킨라빈스은행나무점 |
| 13953 | 배스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 강남대로 390 | 127.028565 | 37.497832 | 배스킨라빈스 |
| 14201 | 베스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 광진구 | 광장동 | 광장동 | 서울특별시 광진구 아차산로 494 | 127.096667 | 37.541145 | 베스킨라빈스 |
df_seoul.loc[df_seoul["상호명_소문자"].str.contains("(베|배)스킨라빈스|baskinrobbins"),
"상호명_소문자"].shape
/Users/yeon/opt/anaconda3/lib/python3.8/site-packages/pandas/core/strings/accessor.py:101: UserWarning: This pattern has match groups. To actually get the groups, use str.extract. return func(self, *args, **kwargs)
(466,)
# 상호명에서 던킨도너츠만 가져옵니다.
# 상호명은 소문자로 변경해 준 컬럼을 사용합니다.
# 던킨|dunkin 의 "상호명_소문자"로 갯수를 세어봅니다.
df_seoul.loc[df_seoul["상호명_소문자"].str.contains("던킨|dunkin"), "상호명_소문자"]
# loc를 이용해 특정 열만 가져오기
1167 던킨도너츠
1819 던킨도너츠테크노마트점
2305 던킨도너츠창동하나로
2342 던킨도너츠용산민자역사2호
3007 던킨도너츠
...
553907 던킨도너츠
554211 던킨도너츠
558894 dunkindoonuts
560984 던킨도너츠
569825 던킨도너츠
Name: 상호명_소문자, Length: 191, dtype: object
# '상호명_소문자'컬럼으로 '배스킨|베스킨|baskin|던킨|dunkin'를 가져와 df_31 변수에 담습니다.
df_31 = df_seoul[df_seoul["상호명_소문자"].str.contains(
"배스킨라빈스|베스킨라빈스|baskinrobbins|던킨|dunkin")].copy()
df_31.shape
(657, 12)
466 + 191
657
# ~은 not을 의미합니다. 베스킨라빈스가 아닌 데이터를 찾을 때 사용하면 좋습니다.
# 아래 코드처럼 결측치를 던킨도너츠로 채워줘도 괜찮습니다.
# df_31["브랜드명"]
# "브랜드명"이라는 새로운 col을 만들어보자
df_31.loc[df_31["상호명_소문자"].str.contains(
"배스킨라빈스|베스킨라빈스|baskinrobbins"), "브랜드명"] = "배스킨라빈스"
df_31[["상호명", "브랜드명"]]
| 상호명 | 브랜드명 | |
|---|---|---|
| 76 | 배스킨라빈스 | 배스킨라빈스 |
| 1167 | 던킨도너츠 | NaN |
| 1819 | 던킨도너츠테크노마트점 | NaN |
| 2164 | 베스킨라빈스 | 배스킨라빈스 |
| 2305 | 던킨도너츠창동하나로 | NaN |
| ... | ... | ... |
| 558894 | DUNKINDOONUTS | NaN |
| 560984 | 던킨도너츠 | NaN |
| 561929 | 배스킨라빈스31 | 배스킨라빈스 |
| 561930 | 배스킨라빈스31 | 배스킨라빈스 |
| 569825 | 던킨도너츠 | NaN |
657 rows × 2 columns
# 'df_31에 담긴 상호명','브랜드명'으로 미리보기를 합니다.
# df_31.loc[~df_31["상호명_소문자"].str.contains(
# "배스킨라빈스|베스킨라빈스|baskinrobbins"), "브랜드명"]
df_31["브랜드명"] = df_31["브랜드명"].fillna("던킨도너츠")
df_31["브랜드명"]
# fillna : "브랜드명"의 결측치를 "던킨도너츠"로 채워줌
76 배스킨라빈스
1167 던킨도너츠
1819 던킨도너츠
2164 배스킨라빈스
2305 던킨도너츠
...
558894 던킨도너츠
560984 던킨도너츠
561929 배스킨라빈스
561930 배스킨라빈스
569825 던킨도너츠
Name: 브랜드명, Length: 657, dtype: object
# 데이터가 제대로 모아졌는지 확인합니다.
# "상권업종대분류명"을 value_counts 를 통해 빈도수를 계산합니다.
df_31["상권업종대분류명"].value_counts()
음식 655 생활서비스 1 소매 1 Name: 상권업종대분류명, dtype: int64
# "상권업종대분류명"컬럼에서 isin 기능을 사용해서 "소매", "생활서비스" 인 데이터만 가져옵니다.
df_31[df_31["상권업종대분류명"].isin(["소매", "생활서비스"])]
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | 브랜드명 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 358699 | 배스킨라빈스 | 소매 | 종합소매점 | 할인점 | 서울특별시 | 강남구 | 압구정동 | 신사동 | 서울특별시 강남구 압구정로 204 | 127.029381 | 37.527375 | 배스킨라빈스 | 배스킨라빈스 |
| 556592 | baskinrobbins | 생활서비스 | 광고/인쇄 | 인쇄종합 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 강남대로 396 | 127.028289 | 37.498154 | baskinrobbins | 배스킨라빈스 |
# "상권업종대분류명"에서 "소매", "생활서비스"는 제외합니다.
df_31 = df_31[~df_31["상권업종대분류명"].isin(["소매", "생활서비스"])].copy()
df_31.shape
# 행 2개 줄어든 것 볼 수 있음!
(655, 13)
# value_counts 로 "브랜드명"의 빈도수를 구합니다.
brand_count = df_31["브랜드명"].value_counts()
brand_count
배스킨라빈스 464 던킨도너츠 191 Name: 브랜드명, dtype: int64
df_31["브랜드명"].value_counts().plot.barh()
<AxesSubplot:>
# normalize=True 로 빈도수의 비율을 구합니다.
df_31["브랜드명"].value_counts(normalize=True).plot.barh()
<AxesSubplot:>
brand_count.index
Index(['배스킨라빈스', '던킨도너츠'], dtype='object')
# countplot 을 그립니다.
g = sns.countplot(data=df_31, x="브랜드명")
for i, value in enumerate(brand_count.index):
g.text(x=i, y=brand_count[i], s=brand_count[i])
# 시군구명으로 빈도수를 세고 브랜드명으로 색상을 다르게 표현하는 countplot 을 그립니다.
plt.figure(figsize=(15, 4))
g = sns.countplot(data=df_31, x="시군구명", hue="브랜드명")
# 대체적으로 던킨보다 배라 매장이 많다!
# Pandas 의 plot 으로 scatterplot 을 그립니다.
df_31[["위도", "경도"]].plot.scatter(x="경도", y="위도")
<AxesSubplot:xlabel='경도', ylabel='위도'>
# seaborn의 scatterplot 으로 hue에 브랜드명을 지정해서 시각화 합니다.
sns.scatterplot(data=df_31, x="경도", y="위도", hue="브랜드명")
# seaborn의 편리함 : 색상 표현(hue)
<AxesSubplot:xlabel='경도', ylabel='위도'>
# 위에서 그렸던 그래프를 jointplot 으로 kind="hex" 을 사용해 그려봅니다.
sns.jointplot(data=df_31, x="경도", y="위도")
# jointplot : scatterplot과 histogram을 같이 그려줌
# 경도, 위도도 어디에 더 빈도수가 많은지 판단 가능
# kind의 기본값은 scatter
<seaborn.axisgrid.JointGrid at 0x7fd43c9e8100>
sns.jointplot(data=df_31, x="경도", y="위도", kind="hex")
# 강남, 서초, ... 에 많은 편
# 빈도수에 따라 색이 진하고 옅음을 통해 수의 많고 적음을 알 수 있음
<seaborn.axisgrid.JointGrid at 0x7fd43b0c6580>


# 아나콘다에서 folium 을 사용하기 위해서는 별도의 설치가 필요
# https://anaconda.org/conda-forge/folium
# conda install -c conda-forge folium
# 지도 시각화를 위한 라이브러리
import folium
# 지도의 중심을 지정하기 위해 위도와 경도의 평균을 구합니다.
lat = df_31["위도"].mean()
long = df_31["경도"].mean()
lat, long
(37.548567678569086, 126.99419527148791)
# 샘플을 하나 추출해서 지도에 표시해 봅니다.
m = folium.Map([lat, long])
# 127.039032 37.495593
folium.Marker(
[37.495593, 127.0390323],
popup="<i>던킨도너츠</i>",
tooltip="던킨도너츠").add_to(m)
m
# folium 사용법을 보고 일부 데이터를 출력해 봅니다.
df_31.sample(random_state=31)
# sample()은 random하게 데이터를 추출해줌
# 항상 같은 값 가져오게 하고싶으면 random_state 지정
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | 브랜드명 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 276889 | 던킨도너츠 | 음식 | 패스트푸드 | 도너츠전문 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 논현로 341 | 127.039032 | 37.495593 | 던킨도너츠 | 던킨도너츠 |
# html 파일로 저장하기
# tooltip 의 한글이 깨져보인다면 html 파일로 저장해서 보세요.
m.save("index.html")
# 데이터프레임의 인덱스만 출력합니다.
df_31.index
Int64Index([ 76, 1167, 1819, 2164, 2305, 2342, 3007, 11060,
13042, 13925,
...
554896, 555145, 557464, 557822, 558006, 558894, 560984, 561929,
561930, 569825],
dtype='int64', length=655)
# icon=folium.Icon(color=icon_color) 로 아이콘 컬러를 변경합니다.
m = folium.Map([lat, long], zoom_start=12)
for i in df_31.index:
sub_lat = df_31.loc[i, "위도"]
sub_long = df_31.loc[i, "경도"]
title = df_31.loc[i, "상호명"] + "-" + df_31.loc[i, "도로명주소"]
icon_color = "blue"
if df_31.loc[i, "브랜드명"] == "던킨도너츠":
icon_color = "red"
folium.Marker(
[sub_lat, sub_long],
icon=folium.Icon(color=icon_color),
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
m
# 던킨은 red, 배라는 blue
# 배라가 훨씬 많구나!
# 둘의 매장이 굉장히 근처구나
# icon=folium.Icon(color=icon_color) 로 아이콘 컬러를 변경합니다.
# 마커가 겹쳐지는 것을 cluster로 표현하기 -> 겹쳐진 것은 숫자로 !
from folium.plugins import MarkerCluster #추가
m = folium.Map([lat, long], zoom_start=12)
marker_cluster = MarkerCluster().add_to(m) #추가
for i in df_31.index:
sub_lat = df_31.loc[i, "위도"]
sub_long = df_31.loc[i, "경도"]
title = df_31.loc[i, "상호명"] + "-" + df_31.loc[i, "도로명주소"]
icon_color = "blue"
if df_31.loc[i, "브랜드명"] == "던킨도너츠":
icon_color = "red"
folium.Marker(
[sub_lat, sub_long],
icon=folium.Icon(color=icon_color),
popup=f'<i>{title}</i>',
tooltip=title).add_to(marker_cluster) #변경
m
df_seoul["상호명"].str.extract("뚜레(주|쥬)르")[0].value_counts()
쥬 257 주 1 Name: 0, dtype: int64
# str.contains 를 사용해서 뚜레(주|쥬)르|파리(바게|크라상) 으로 상호명을 찾습니다.
# df_bread 라는 데이터프레임에 담습니다.
df_bread = df_seoul[df_seoul["상호명"].str.contains("뚜레(주|쥬)르|파리(바게|크라상)")].copy()
print(df_bread.shape)
df_bread
# 바게뜨 / 바게트
(825, 12)
/Users/yeon/opt/anaconda3/lib/python3.8/site-packages/pandas/core/strings/accessor.py:101: UserWarning: This pattern has match groups. To actually get the groups, use str.extract. return func(self, *args, **kwargs)
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2935 | 뚜레쥬르 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 노원구 | 공릉2동 | 공릉동 | 서울특별시 노원구 공릉로 213 | 127.077295 | 37.628289 | 뚜레쥬르 |
| 13843 | 뚜레쥬르 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 서초구 | 서초4동 | 서초동 | 서울특별시 서초구 서초대로 411 | 127.025904 | 37.498098 | 뚜레쥬르 |
| 14031 | 파리바게뜨길동사거리점 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 강동구 | 성내3동 | 성내동 | 서울특별시 강동구 천호대로 1128 | 127.136501 | 37.534154 | 파리바게뜨길동사거리점 |
| 14229 | 파리바게뜨상계제일점 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 노원구 | 상계10동 | 상계동 | 서울특별시 노원구 노원로 540 | 127.059227 | 37.661367 | 파리바게뜨상계제일점 |
| 14246 | 뚜레쥬르중계브라운 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 노원구 | 중계2.3동 | 중계동 | 서울특별시 노원구 동일로203가길 29 | 127.064245 | 37.639918 | 뚜레쥬르중계브라운 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 559820 | 파리바게뜨 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 송파구 | 위례동 | 장지동 | 서울특별시 송파구 위례광장로 136 | 127.142223 | 37.477113 | 파리바게뜨 |
| 561538 | 파리바게뜨 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 강서구 | 방화1동 | 마곡동 | 서울특별시 강서구 마곡서1로 139-13 | 126.818015 | 37.569257 | 파리바게뜨 |
| 561810 | 파리바게뜨 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 관악구 | 청룡동 | 봉천동 | 서울특별시 관악구 남부순환로218길 1 | 126.950620 | 37.480955 | 파리바게뜨 |
| 569327 | 파리바게뜨 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 마포구 | 상암동 | 상암동 | 서울특별시 마포구 성암로 267 | 126.890966 | 37.581110 | 파리바게뜨 |
| 569479 | 파리바게뜨 | 음식 | 제과제빵떡케익 | 제과점 | 서울특별시 | 동대문구 | 휘경2동 | 휘경동 | 서울특별시 동대문구 망우로 106 | 127.065123 | 37.590647 | 파리바게뜨 |
825 rows × 12 columns
# 잘못 가져온 데이터가 있는지 확인합니다.
df_bread["상권업종대분류명"].value_counts()
음식 823 학문/교육 2 Name: 상권업종대분류명, dtype: int64
# 제과점과 상관 없을 것 같은 상점을 추출합니다.
df_bread[df_bread["상권업종대분류명"] == "학문/교육"]
| 상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 354693 | 파리바게뜨교육소 | 학문/교육 | 학원-자격/국가고시 | 학원-제과기술 | 서울특별시 | 영등포구 | 영등포동 | 영등포동8가 | 서울특별시 영등포구 영중로 159 | 126.905405 | 37.530553 | 파리바게뜨교육소 |
| 406627 | 뚜레쥬르 | 학문/교육 | 학원-자격/국가고시 | 학원-제과기술 | 서울특별시 | 금천구 | 가산동 | 가산동 | 서울특별시 금천구 가산디지털1로 128 | 126.883684 | 37.477224 | 뚜레쥬르 |
# "상권업종대분류명"이 "학문/교육"이 아닌 것만 가져옵니다.
print(df_bread.shape)
df_bread = df_bread[df_bread["상권업종대분류명"] != "학문/교육"].copy()
print(df_bread.shape)
(825, 12) (823, 12)
# 상호명의 unique 값을 봅니다.
df_bread["상호명"].unique()
array(['뚜레쥬르', '파리바게뜨길동사거리점', '파리바게뜨상계제일점', '뚜레쥬르중계브라운', '파리바게뜨-판매옥수점',
'파리바게뜨당고개점', '파리바게뜨목동오거리점', '뚜레쥬르신당역점', '파리바게뜨', '파리바게뜨서강신수점',
'파리크라상', '파리바게뜨수유중앙점', '파리바게뜨가락중앙점', '파리바게뜨종로구기',
'뚜레쥬르왕십리민자역사점왕십리민자역사점', '파리크라상교대역점', '뚜레쥬르도선사거리점', '여의도2호파리크라상',
'목동파리크라상', '뚜레쥬르개봉역점', '파리바게뜨외대점', '파리크라상파스쿠찌홍', '파리크라상파스쿠찌압',
'CJ뚜레쥬르', '신목파리바게뜨', '방주산업뚜레쥬르광화문경희궁의', '파리크라상파스쿠찌서', '파리크라상파스쿠찌도',
'강동경희파리바게뜨', '파리크라상이대점', '파리크라상파스쿠찌압구정역2호', '뚜레쥬르송천센트레빌점',
'파리크라상잠바주스디큐브', '파리크라상잠바주스대치역', '파리바게트', '상계뚜레쥬르', '뚜레쥬르대림3동점',
'뚜레쥬르목4동점', '카페약수파리바게트', '파리바게뜨가좌역점', '파리바게뜨영등포구청점', '뚜레쥬르독산지식센터점',
'파리바게뜨수락리버시티', '파리바게뜨방학중앙점', '파리바게뜨중계2호점', '뚜레쥬르방화역점', '파리바게뜨중앙대점',
'뚜레쥬르레이크펠리스점', '파리바게뜨장안현대점', '뚜레쥬르우이점', '파리바게뜨성북점', '뚜레쥬르양천푸른점',
'파리바게뜨마장대로점', '파리바게뜨문정역점', '뚜레쥬르엔시티보라매', '파리바게뜨종로시그니처점',
'파리바게뜨상계보람점', '파리바게뜨성동세무서점', '파리바게뜨여의경도점', '파리바게뜨구로제일점',
'뚜레쥬르창동SM마트', '파리바게뜨카페대학로점', '파리바게뜨대림역점', '파리바게뜨월계미성', '파리크라상서래점',
'파리바게뜨금천한양점', '씨제이푸드빌뚜레주르', '파리바게뜨휘경점', '씨제이푸드빌뚜레쥬르대학',
'파리크라상키친올림픽공원점', '파리바게뜨역', '파리크라상잠바주스동', '파리크라상강남리나스',
'파리바게트은평뉴타운', '파리크라상잠바주스삼', '뚜레쥬르빨라쪼CU가산디폴', '파리바게트상도건영',
'파리크라상르노뜨로', '파리바게뜨망우중앙', '파리바게뜨군자역점', '파리바게뜨당산포스빌',
'파리크라상파리바게뜨신분당', '파리크라상서초아크로비스', '파리바게뜨난곡점', '파리크라상파리바게뜨카페',
'파리바게뜨쌍문사거리', '파리크라상파스쿠찌신촌연', '파리바게뜨카페하월곡동일점', '길음역파리바게뜨',
'파리바게트종암사거리', '파리바게뜨까페', '파리바게뜨구로고대', '파리바게뜨평창점', '파리크라상역삼정',
'파리크라상더월드바인', '뚜레쥬르월곡래미안점', '씨제이푸드빌뚜레쥬르연대', '카페뚜레쥬르', '파리바게트2011년',
'파리바게뜨신분당선', '파리바게뜨사러가', '뚜레쥬르우장산역점', '회기역파리바게뜨', '뚜레쥬르명동역점',
'파리바게뜨동대문구청점', '뚜레쥬르풍납현대점', '파리바게뜨올림픽승리점', '뚜레쥬르구로IT점', '파리바게뜨도봉점',
'파리바게뜨동교삼거리점', '파리바게뜨카페당산동행복점', '파리바게뜨묵동삼거리점', '뚜레쥬르시흥사거리점',
'파리바게뜨자양2호점', '파리바게뜨사당신동아점', '파리바게뜨불광역점', '뚜레쥬르상월곡역', '파리바게뜨낙성대역점',
'뚜레쥬르사당시티점', '뚜레쥬르대림우성점', '파리바게뜨북가좌점', '파리바게뜨강남구청센터점', '파리바게뜨중곡역점',
'파리바게뜨가재울래미안점', '파리바게뜨종로세무서점', '파리바게뜨충무로점', '파리바게뜨-뚝섬점',
'파리바게뜨문정카페', '파리바게뜨마곡엠밸리점', '뚜레쥬르쌍문선덕', '파리바게뜨창동역동부점', '파리바게뜨마천점',
'파리바게뜨염창2호점', '명동역남산파리바게뜨', '파리바게뜨신대림자이', '파리바게뜨정동점', '파리바게트마포',
'군자사랑파리바게뜨', '파리바게뜨논현동점', '파리바게뜨신길돈보스코점', '뚜레쥬르은평뉴타운', '파리바게뜨망원점',
'파리바게뜨당산역삼성', '적십자파리바게뜨', '파리바게트합정역', '파리바게뜨창동서부점', '파리바게뜨회기역점',
'뚜레쥬르성내3동점', '파리바게뜨강일리버파크점', '파리바게뜨상계백병원점', '파리바게뜨번동지점',
'뚜레쥬르화곡역점', '파리바게뜨마포합정역점', '뚜레쥬르구의점', '파리바게뜨논현경복점', '파리바게뜨월곡두산점',
'뚜레쥬르공덕역점', '파리바게뜨동답한신점', '뚜레쥬르국립중앙의료원점', '파리바게뜨구산역점', '뚜레쥬르공릉2동점',
'파리바게뜨개포행복점', '뚜레쥬르영등포역', '파리바게뜨강서하이웨이점', '파리바게뜨도봉1동점',
'파리바게뜨보라매타운점', '뚜레쥬르건대스타시티점', '파리바게뜨발산중앙점', '파리바게뜨중랑역점',
'파리바게뜨테헤란로점', '파리바게뜨선릉아이타워점', '파리바게뜨내발산', '파리바게뜨강남을지병원점',
'파리바게뜨동서울터미널점', '파리바게뜨신당역아크로점', '파리바게뜨방이1동점', '뚜레쥬르구의1동점',
'파리바게뜨온수남부점', '파리바게뜨강남삼성점', '파리바게뜨연희안산점', '파리바게뜨카페전농삼성점',
'파리바게뜨2001아울렛중계점', '뚜레쥬르상도래미안점', '파리바게뜨목동8단지점', '파리바게뜨방이점',
'파리바게뜨번동점', '파리바게뜨청담사거리점', '파리바게뜨강남중앙점', '파리바게뜨관악현대점', '파리바게뜨압구정점',
'뚜레쥬르용마산역점', '파리바게뜨잠실5단지', '뚜레쥬르서울대병원', '파리바게뜨이화사랑점', '뚜레쥬르구의역점',
'파리바게뜨이수자이점', '파리바게뜨카페신사점', '파리크라상압구정역점', '파리바게뜨일원밀알',
'파리바게뜨한강타운점', '파리바게뜨역삼래미안점', '뚜레쥬르화곡옛길점', '뚜레쥬르마포도화점', '파리바게뜨청량리점',
'파리바게뜨올림픽점', '뚜레쥬르신도림태영점', '뚜레쥬르독립문역', '뚜레쥬르고덕아이파크', '파리바게뜨면목역점',
'뚜레쥬르삼성힐스테이트점', '파리바게뜨송파레미안점', '파리바게뜨당곡사거리점', '파리바게뜨연희대우점',
'파리바게뜨연신내', '파리바게뜨사당파스텔시티', '파리바게뜨반포타운', '파리바게뜨신림신원점',
'파리바게뜨동서신의학점', '파리바게뜨서울대입구역점', '파리바게뜨홍대점', '뚜레쥬르강서구청점', '파리바게뜨행당점',
'파리바게뜨하계벽산점', '파리바게뜨암사브라운스톤점', '파리바게뜨성수코오롱점', '파리크라상홍대점',
'파리크라상키친삼성역점', '뚜레쥬르신이문', '뚜레쥬르둔촌대우', '파리바게뜨대치하얏트점', '파리바게뜨삼성카페점',
'파리바게뜨개봉역점', '파리바게뜨신금호역점', '파리바게뜨대림시장점', '뚜레쥬르배명사거리점', '파리바게뜨학동역점',
'파리크라상샌드위치서울역', '파리바게뜨수서동성당점', '뚜레쥬르종로구청점', '위례아이파크파리바게뜨',
'파리크라상강남점', '파리바게뜨성내삼성역', '파리바게트상일', '파리바게뜨금호역점', '뚜레쥬르독립문',
'파리바게뜨뱅뱅사거리점', '파리바게뜨고덕래미안힐스I점', '파리바게트정릉국민대점2호', '파리바게뜨육사화랑회관점',
'파리크라상연세세브란스점', '파리바게뜨은평뉴타운2지구점', '뚜레쥬르구로개봉점', '파리바게뜨마곡힐스테이트',
'파리바게뜨수색역점', '파리바게뜨금천롯데캐슬점', '뚜레쥬르카페안암역점', '뚜레쥬르공덕해링턴점', '파리바게트카페',
'파리바게뜨압구정현대점', '뚜레쥬르왕십리센트라스점', '파리바게트혜화로타리', '파리바게뜨개봉푸르뫼점',
'파리바게뜨신풍역점', '파리바게뜨올림픽승리', '파리바게뜨제기동역점', '뚜레쥬르응암오거리',
'파리바게뜨금천롯데캐슬', '파리바게뜨마포점', '파리바게트은평신사', '파리바게뜨신촌현대', '파리바게뜨신림역점',
'파리바게뜨종로구청', '국회의사당뚜레쥬르', '파리바게트역촌2호', '뚜레쥬르관악우림', '뚜레쥬르신풍역',
'파리바게뜨동답한신', '파리바게뜨은평뉴타운', '뚜레쥬르무악재', '뚜레쥬르신길삼거리', '파리바게트곰달래',
'파리바게트종로3가', '파리바게트역삼스타', '파리바게뜨한강성심병원점', '뚜레쥬르양천판교', '뚜레쥬르구의1동',
'가락중앙파리바게뜨', '씨제이뚜레쥬르', '은천갈입구파리바게뜨', '씨제이푸드빌뚜레쥬르배명사거리',
'파리바게뜨천호행복', '파리바게트우면동', '파리바게뜨미아삼거리역', '파리바게뜨청담사거리', '파리바게뜨해피석수',
'뚜레쥬르카페대치점', '파리바게뜨삼성카페', '파리바게뜨동국대', '파리바게뜨중계두타빌', '파리바게뜨역삼초교',
'파리바게트14478카페마로니에', '파리바게트갤러리아팰리스', '파리바게뜨은평뉴타운3지구', '파리바게뜨사가정',
'파리바게뜨상도역', '파리바게뜨당고개', '파리바게뜨상계대림', '파리바게뜨상봉한일', '파리바게트가산디지털',
'파리바게뜨을지로3가역', '씨제이뚜레쥬르풍납현대', '파리바게트방화', '파리바게트13275상일중앙',
'파리바게뜨강동경희', '뚜레쥬르강서보건소', '뚜레쥬르양천캐슬', '뚜레쥬르숙대입구', '뚜레쥬르성내3동',
'파리바게트방화역', '파리바게트삼성화재', '파리바게트사당신동아', '파리바게뜨삼성삼익', '파리바게뜨양재드림',
'파리바게뜨온수역', '파리바게트서초참누리인셉터', '파리바게뜨창동제일', '파리바게뜨양평비즈타워', '파리바게뜨논현',
'파리바게뜨카페', '파리바게트도곡렉슬', '파리바게뜨방학선덕', '파리바게트17789위례아이파크',
'파리바게트선릉아이타워인셉터', '뚜레쥬르신림역점', '파리바게트반포제일'], dtype=object)
# 상호명이 '파스쿠찌|잠바주스'가 아닌 것만 가져오세요.
print(df_bread.shape)
df_bread = df_bread[~df_bread["상호명"].str.contains('파스쿠찌|잠바주스')].copy()
print(df_bread.shape)
(823, 12) (812, 12)
# 브랜드명 컬럼을 만듭니다. "파리바게뜨" 에 해당되는 데이터에 대한 값을 채워줍니다.
# 파리크라상에 대한 처리를 따로 해주세요!
df_bread.loc[df_bread["상호명"].str.contains("파리바게"), "브랜드명"] = "파리바게뜨"
df_bread[["상호명", "브랜드명"]].head()
| 상호명 | 브랜드명 | |
|---|---|---|
| 2935 | 뚜레쥬르 | NaN |
| 13843 | 뚜레쥬르 | NaN |
| 14031 | 파리바게뜨길동사거리점 | 파리바게뜨 |
| 14229 | 파리바게뜨상계제일점 | 파리바게뜨 |
| 14246 | 뚜레쥬르중계브라운 | NaN |
# 브랜드명 컬럼의 결측치는 "뚜레쥬르" 이기 때문에 fillna 를 사용해서 값을 채웁니다.
df_bread["브랜드명"] = df_bread["브랜드명"].fillna("뚜레쥬르")
df_bread[["상호명", "브랜드명"]].head()
| 상호명 | 브랜드명 | |
|---|---|---|
| 2935 | 뚜레쥬르 | 뚜레쥬르 |
| 13843 | 뚜레쥬르 | 뚜레쥬르 |
| 14031 | 파리바게뜨길동사거리점 | 파리바게뜨 |
| 14229 | 파리바게뜨상계제일점 | 파리바게뜨 |
| 14246 | 뚜레쥬르중계브라운 | 뚜레쥬르 |
# 브랜드명의 빈도수를 봅니다.
df_bread["브랜드명"].value_counts()
파리바게뜨 555 뚜레쥬르 257 Name: 브랜드명, dtype: int64
# 빈도수를 비율로 보기
df_bread["브랜드명"].value_counts(normalize=True)
파리바게뜨 0.683498 뚜레쥬르 0.316502 Name: 브랜드명, dtype: float64
# countplot 으로 브랜드명을 그려봅니다.
sns.countplot(data=df_bread, x="브랜드명")
<AxesSubplot:xlabel='브랜드명', ylabel='count'>
# 시군구별로 브랜드명의 빈도수 차이를 비교합니다.
plt.figure(figsize=(15, 4))
sns.countplot(data=df_bread, x="시군구명", hue="브랜드명")
# 파리바게트 매장이 전반적으로 더 많다.
<AxesSubplot:xlabel='시군구명', ylabel='count'>
# scatterplot 으로 위경도를 표현해 봅니다.
sns.scatterplot(data=df_bread, x="경도", y="위도", hue="브랜드명")
<AxesSubplot:xlabel='경도', ylabel='위도'>
# jointplot 으로 위경도를 표현해 봅니다.
sns.jointplot(data=df_bread, x="경도", y="위도", kind="hex")
<seaborn.axisgrid.JointGrid at 0x7fd3eb4684f0>
df_bread.index
Int64Index([ 2935, 13843, 14031, 14229, 14246, 14713, 14842, 14889,
14897, 15019,
...
544366, 544527, 551365, 555475, 556168, 559820, 561538, 561810,
569327, 569479],
dtype='int64', length=812)
df_bread.loc[2935, "상호명"]
'뚜레쥬르'
# for i in df_bread.index:
# print(i)
m = folium.Map([lat, long])
for i in df_bread.index:
sub_lat = df_bread.loc[i, "위도"]
sub_long = df_bread.loc[i, "경도"]
title = df_bread.loc[i, "상호명"] + " - " + df_bread.loc[i, "도로명주소"]
icon_color = "blue"
if df_bread.loc[i, "브랜드명"] == "뚜레쥬르":
icon_color = "green"
folium.Marker(
[sub_lat, sub_long],
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
m.save('index.html')
m
# icon=folium.Icon(color=icon_color) 로 아이콘 컬러를 변경합니다.
m = folium.Map([lat, long])
for i in df_bread.index:
sub_lat = df_bread.loc[i, "위도"]
sub_long = df_bread.loc[i, "경도"]
title = df_bread.loc[i, "상호명"] + " - " + df_bread.loc[i, "도로명주소"]
icon_color = "blue"
if df_bread.loc[i, "브랜드명"] == "뚜레쥬르":
icon_color = "green"
folium.Marker(
[sub_lat, sub_long],
icon=folium.Icon(color=icon_color),
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
m.save('index.html')
m
# icon=folium.Icon(color=icon_color) 로 아이콘 컬러를 변경합니다.
m = folium.Map([lat, long], zoom_start=12, tiles="stamen toner")
for i in df_bread.index:
sub_lat = df_bread.loc[i, "위도"]
sub_long = df_bread.loc[i, "경도"]
title = df_bread.loc[i, "상호명"] + " - " + df_bread.loc[i, "도로명주소"]
icon_color = "blue"
if df_bread.loc[i, "브랜드명"] == "뚜레쥬르":
icon_color = "green"
folium.CircleMarker(
[sub_lat, sub_long],
radius=3,
color=icon_color,
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
m.save('index.html')
m
from folium.plugins import MarkerCluster
m = folium.Map([lat, long], zoom_start=12, tiles="stamen toner")
marker_cluster = MarkerCluster().add_to(m)
for i in df_bread.index:
sub_lat = df_bread.loc[i, "위도"]
sub_long = df_bread.loc[i, "경도"]
title = df_bread.loc[i, "상호명"] + " - " + df_bread.loc[i, "도로명주소"]
icon_color = "blue"
if df_bread.loc[i, "브랜드명"] == "뚜레쥬르":
icon_color = "green"
folium.CircleMarker(
[sub_lat, sub_long],
radius=3,
color=icon_color,
popup=f'<i>{title}</i>',
tooltip=title).add_to(marker_cluster)
m
# heatmap 예제 이해하기
# 색깔을 통해 많고 적음을 알 수 있음
data = (
np.random.normal(size=(100, 3)) *
np.array([[1, 1, 1]]) +
np.array([[48, 5, 1]])
).tolist()
data[:5]
[[46.698601719317466, 5.293409449489297, 1.1009685930179627], [49.40286747690017, 6.0475397566656035, 2.2803700337247905], [47.2460228861894, 4.800491802386493, -0.017350945472705437], [48.04719632140916, 6.232302400886443, -0.1319700649558071], [48.5309478812891, 4.164047125720366, 0.3746693070999222]]
# heatmap 예제와 같은 형태로 데이터 2차원 배열 만들기
heat = df_bread[["위도", "경도", "브랜드명"]].copy()
heat.head()
| 위도 | 경도 | 브랜드명 | |
|---|---|---|---|
| 2935 | 37.628289 | 127.077295 | 뚜레쥬르 |
| 13843 | 37.498098 | 127.025904 | 뚜레쥬르 |
| 14031 | 37.534154 | 127.136501 | 파리바게뜨 |
| 14229 | 37.661367 | 127.059227 | 파리바게뜨 |
| 14246 | 37.639918 | 127.064245 | 뚜레쥬르 |
heat["브랜드명"]
2935 뚜레쥬르
13843 뚜레쥬르
14031 파리바게뜨
14229 파리바게뜨
14246 뚜레쥬르
...
559820 파리바게뜨
561538 파리바게뜨
561810 파리바게뜨
569327 파리바게뜨
569479 파리바게뜨
Name: 브랜드명, Length: 812, dtype: object
heat["브랜드명"] = heat["브랜드명"].replace("뚜레쥬르", 1).replace("파리바게뜨", -1)
heat
| 위도 | 경도 | 브랜드명 | |
|---|---|---|---|
| 2935 | 37.628289 | 127.077295 | 1 |
| 13843 | 37.498098 | 127.025904 | 1 |
| 14031 | 37.534154 | 127.136501 | -1 |
| 14229 | 37.661367 | 127.059227 | -1 |
| 14246 | 37.639918 | 127.064245 | 1 |
| ... | ... | ... | ... |
| 559820 | 37.477113 | 127.142223 | -1 |
| 561538 | 37.569257 | 126.818015 | -1 |
| 561810 | 37.480955 | 126.950620 | -1 |
| 569327 | 37.581110 | 126.890966 | -1 |
| 569479 | 37.590647 | 127.065123 | -1 |
812 rows × 3 columns
heat = heat.values # 값만 가져오기
heat
array([[ 37.62828881, 127.07729473, 1. ],
[ 37.49809817, 127.02590362, 1. ],
[ 37.53415376, 127.13650069, -1. ],
...,
[ 37.48095516, 126.95062029, -1. ],
[ 37.5811105 , 126.89096576, -1. ],
[ 37.59064662, 127.06512283, -1. ]])
heat[:5]
array([[ 37.62828881, 127.07729473, 1. ],
[ 37.49809817, 127.02590362, 1. ],
[ 37.53415376, 127.13650069, -1. ],
[ 37.66136731, 127.059227 , -1. ],
[ 37.63991755, 127.06424515, 1. ]])
# HeatMap 그리기
import folium
from folium.plugins import HeatMap
m = folium.Map([lat, long], tiles="stamentoner", zoom_start=12)
HeatMap(heat).add_to(m)
m.save('Heatmap.html')
m
# 아쉽게도 뚜레쥬르, 파리바게뜨 구분은 x
# heatmatp & circlemarker 합치기
from folium.plugins import HeatMap
m = folium.Map([lat, long], tiles="stamentoner", zoom_start=12)
for i in df_bread.index:
sub_lat = df_bread.loc[i, "위도"]
sub_long = df_bread.loc[i, "경도"]
title = df_bread.loc[i, "상호명"] + " - " + df_bread.loc[i, "도로명주소"]
icon_color = "blue"
if df_bread.loc[i, "브랜드명"] == "뚜레쥬르":
icon_color = "green"
folium.CircleMarker(
[sub_lat, sub_long],
radius=3,
color=icon_color,
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
HeatMap(heat).add_to(m)
m